'''
* This is the projet for Brtc LlmOps Platform
* @Author Leon-liao <liaosiliang@alltman.com>
* @Description //TODO 
* @File: document_schema.py
* @Time: 2025/9/26
* @All Rights Reserve By Brtc
'''
import uuid

from flask_wtf import FlaskForm
from marshmallow import Schema, fields, pre_dump
from wtforms import StringField, BooleanField
from wtforms.validators import DataRequired, AnyOf
from internal.entity.dataset_entity import ProcessType, DEFAULT_PROCESS_RULE
from internal.exception.exception import ValidateErrorException
from internal.model import Document
from internal.schema.schema import ListField, DictField

class CreateDocumentReq(FlaskForm):
    """创建&新增文档列表请求"""
    upload_file_ids = ListField("upload_file_ids")
    process_type = StringField("process_type", validators=[
        DataRequired("文档处理类型不能为空"),
        AnyOf(values = [ProcessType.AUTOMATIC, ProcessType.CUSTOM], message="=处理类型格式错误！")
    ])
    rule = DictField()

    def validate_upload_file_ids(self, field:ListField)->None:
        """校验上传的文件id 列表"""
        #1、检验数据类型与非空
        if not isinstance(field.data, list):
            raise ValidateErrorException("文件 id 列表格式必须是数组！！")
        #2、检验数据长度，最长不能超过10条记录
        if len(field.data) == 0 or len(field.data) > 10:
            raise ValidateErrorException("处理的文档数量不能超过 10条！！")
        #3、循环校验id 是否为uuid
        for  up_id in field.data:
            try:
                uuid.UUID(up_id)
            except Exception as e:
                raise ValidateErrorException("文件id 的格式必须要是 UUID")

    def validate_rule(self, field:DictField):
        """校验处理规则"""
        #1、校验处理模式， 如果为自动， 则手动为rule 赋值
        if self.process_type.data == ProcessType.AUTOMATIC:
            field.data = DEFAULT_PROCESS_RULE["rule"]
        else:
            #2、检测自定义处理器下面是否传递了rule
            if not isinstance(field.data, dict) or len(field.data) == 0:
                raise ValidateErrorException("自定义处理模式下, rule 不能为空！")

            #3、校验pre_process_rules， 涵盖非空列表类型
            if "pre_process_rules" not in field.data or not isinstance(field.data["pre_process_rules"], list):
                raise ValidateErrorException("pre_process_rule 字段必须是列表！！")

            #4、提取pre_process_rules 中唯一的处理规则， 避免重复处理
            unique_pre_process_rule_dict = {}
            for pre_process_rule in field.data["pre_process_rules"]:
                #5、校验id 参数非空、id 是否规范
                if ("id" not in pre_process_rule
                        or
                   pre_process_rule["id"] not in ["remove_extra_space", "remove_url_and_email"]):
                    raise ValidateErrorException("pre_process_rules  的 id 格式错误！！")
                #6、检验enable 参数，涵盖非空、布尔值
                if "enabled" not in pre_process_rule or not isinstance(pre_process_rule["enabled"], bool):
                    raise ValidateErrorException("pre_process_rule 的 enable  字段错误！！")
                #7、将数据添加到唯一字典中
                unique_pre_process_rule_dict[pre_process_rule["id"]] ={
                    "id":pre_process_rule["id"],
                    "enabled":pre_process_rule["enabled"]
                }

            #8、判断一下是否传递了两个处理规则
            if len(unique_pre_process_rule_dict) !=2:
                raise ValidateErrorException("pre_prcess_rule必须为两个！")

            #9、将处理后的数据 转换成为列表
            field.data["pre_process_rule"] = list(unique_pre_process_rule_dict.values())

            #10、检验分段参数segments，涵盖非空、字典
            if "segment" not in field.data or not isinstance(field.data["segment"], dict):
                raise ValidateErrorException("segment 字段不能为空且为字典！")

            #11、校验分隔符separators,涵盖非空、列表、子元素为字符串
            if "separators" not in field.data["segment"] or not  isinstance(field.data["segment"]["separators"], list):
                raise ValidateErrorException("separators 分割符不能为空且为列表")
            for separator in field.data["segment"]["separators"]:
                if not isinstance(separator, str):
                    raise ValidateErrorException("分隔符列表火元素类型必须为字符串！")
            if len(field.data["segment"]["separators"]) == 0:
                raise ValidateErrorException("分割符元素列表不能为空！！")

            #12、简要分块大小chunk_size，涵盖非空 数字
            if "chunk_size" not in field.data["segment"] or not isinstance(field.data["segment"]["chunk_size"], int):
                raise ValidateErrorException("分割块大小必须是数字且不能为空！")
            if field.data["segment"]["chunk_size"]<100 or field.data["segment"]["chunk_size"] > 1000:
                raise ValidateErrorException("分割块大小必须是100-1000的范围！")

            #13、校验块重叠大小chunk_overlap，含盖非空\数字、范围
            if "chunk_overlap" not in field.data["segment"] or not isinstance(field.data["segment"]["chunk_overlap"], int):
                raise ValidateErrorException("chunk_overlap块重叠大小不能为空且为整数！！")

            if not (0<= field.data["segment"]["chunk_overlap"] <= field.data["segment"]["chunk_size"]/2):
                raise ValidateErrorException(f"块重叠大小应该在 0-{int(field.data['segment']['chunk_size']/2)}之间")

            #14、更新并剔除 多余的数据
            field.data = {
                "pre_process_rules":field.data["pre_process_rules"],
                "segment":{
                    "separators":field.data["segment"]["separators"],
                    "chunk_size": field.data["segment"]["chunk_size"],
                    "chunk_overlap": field.data["segment"]["chunk_overlap"]
                }
            }


class CreateDocumentResp(Schema):
    """创建文档列表响应结构"""
    documents = fields.List(fields.Dict, dump_default=[])
    batch = fields.String(dump_default="")

    @pre_dump
    def process_data(self, data:tuple[list[Document], str], **kwargs):
        return {
            "documents":[{
                "id":document.id,
                "name":document.name,
                "status":document.status,
                "created_at":int(document.created_at.timestamp())
            }for document in data[0]],
            "batch":data[1]
        }

class UpdateDocumentReq(FlaskForm):
    """更新文档状态请求"""
    enabled = BooleanField("enabled")

    def validate_enabled(self, field:BooleanField)->None:
        """校验文档启用状态"""
        if not isinstance(field.data, bool):
            raise ValidateErrorException("enabled 状态不能为空且必须为布尔值！")
